
#########################################################################

# Copyright (C) Flavio Piccinelli 2012 <flavio.picci@gmail.com>

#########################################################################

# MySSL.rb
# This file is part of "AriaAperta".

# AriaAperta is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# AriaAperta is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with AriaAperta.  If not, see <http://www.gnu.org/licenses/>.

#########################################################################
#########################################################################


#########################################################################
# Required libraries
#########################################################################
require "openssl"
require "lib/const"
#########################################################################

module MySSL

	class MySSLServer < OpenSSL::SSL::SSLServer

		def initialize(io, ctx)
			super(io, ctx)
		end
		
		def accept
			sock = @svr.accept
			begin
				ssl = MySSL::MySSLSocket.new(sock, @ctx)
				ssl.sync_close = true
				ssl.accept if @start_immediately
				ssl
			rescue SSLError => ex
				sock.close
				raise ex
			end
		end
		
	end

	class MySSLSocket < OpenSSL::SSL::SSLSocket

		def initialize(io, ctx)
			super(io, ctx)
		end

		def gets_all
			lineIn = self.gets
			if !lineIn.nil?
				lineIn = lineIn.chomp
			else
				puts "connection reset by client"
				Thread.exit
			end
			return lineIn
		end
	end

	def gen_cert(ca_cert, ca_key, client_name, username)
		
		cli_key = OpenSSL::PKey::RSA.new 2048
		cli_cert = OpenSSL::X509::Certificate.new
		cli_cert.version = 2
		cli_cert.serial = 2
		cli_cert.subject = OpenSSL::X509::Name.parse "/DC=Aria_Client/CN=#{client_name}/DN=#{username}"
		cli_cert.issuer = ca_cert.subject
		cli_cert.public_key = cli_key.public_key
		cli_cert.not_before = Time.now
		cli_cert.not_after = cli_cert.not_before + 365 * 24 * 60 * 60 # 1 years validity
		ef = OpenSSL::X509::ExtensionFactory.new
		ef.subject_certificate = cli_cert
		ef.issuer_certificate = ca_cert
		cli_cert.add_extension(ef.create_extension("keyUsage","digitalSignature, keyEncipherment", true))
		cli_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
		cli_cert.sign(ca_key, OpenSSL::Digest::SHA256.new)

		File.open("#{CERT_PATH}#{username}_cert.pem", "w+") do |cert_file|
			cert_file.write cli_cert.to_pem
		end
		File.open("#{CERT_PATH}#{username}_key.pem", "w+") do |key_file|
			key_file.write cli_key.to_pem
		end
		
	end

	def set_contxt(server)
		
		sslContext = OpenSSL::SSL::SSLContext.new
		sslContext.ca_file = "#{CERT_PATH}ca_cert.pem"
		sslContext.cert = OpenSSL::X509::Certificate.new(File.open("#{CERT_PATH}srv_cert.pem"))
		sslContext.key = OpenSSL::PKey::RSA.new(File.open("#{CERT_PATH}srv_key.pem"))
# 		sslContext.verify_mode = OpenSSL::SSL::VERIFY_PEER

		sslServer = MySSL::MySSLServer.new(server, sslContext)

		return sslServer
		
	end

	def get_encr_passwd(username, password)

		passwd_tmp = password + username.hash.to_s
		passwd_encr = OpenSSL::Digest::SHA256.digest(passwd_tmp)

		return passwd_encr
		
	end
	
end
